package primary.code03_Heap;

import java.util.Arrays;

/**
 * 堆排序 (不稳定)
 * 堆（完全二叉树，优先队列） 通过数组实现
 * i   2i+1   2i+2   (i-1)/2
 * <p>
 * swim, sink 操作
 * 时间复杂度 O(N*logN)  空间复杂度 O(1)  不稳定
 */
public class Code01_HeapSort {

    private static void heapSort(int[] arr) {
        if (arr == null || arr.length <= 1) return;
        //堆化
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
//            heapInsertTest(arr, i);
        }
        //堆化（对于一次性给出所有数据，可以使用 heapify，时间复杂度为 heapInsert 的 1/2）
//        for (int i = arr.length - 1; i >= 0; i--) {
//            heapify(arr, i, arr.length - 1);
//        }
        //排序
        for (int i = arr.length - 1; i >= 0; i--) {
            swap(arr, 0, i);
            heapify(arr, 0, i - 1);
//            heapifyTest(arr, 0, i - 1);
        }
    }

    private static void heapSortTest(int[] arr) {
        if (arr == null || arr.length <= 1) {
            return;
        }
        for (int i = arr.length - 1; i >= 0; i--) { // O(N)
            heapifyTest(arr, i, arr.length - 1);
        }
        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i);
            heapifyTest(arr, 0, i - 1);
        }
    }

    private static void heapInsertTest(int[] arr, int index) {
    }

    private static void heapifyTest(int[] arr, int s, int e) {
        int l = 2 * s + 1;
        int r = 2 * s + 2;
        int maxChild = l > e ? -1 : (r <= e && arr[r] >= arr[l] ? r : l); // 较大的子节点
        while (maxChild != -1 && arr[maxChild] > arr[s]) { // 有子节点并大于父节点
            swap(arr, maxChild, s);
            s = maxChild;
            l = 2 * s + 1;
            r = 2 * s + 2;
            maxChild = l > e ? -1 : r <= e && arr[r] >= arr[l] ? r : l;
        }
    }

    /**
     * 将 index 所在位置的数插入到大根堆中
     *
     * @param arr
     * @param index
     */
    private static void heapInsert(int[] arr, int index) {
        while (arr[(index - 1) / 2] < arr[index]) {
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    /**
     * index 所在位置的数被替换后，重新堆化（左右二叉树为堆）
     *
     * @param arr
     * @param index
     * @param end   堆最后一个节点的索引
     */
    private static void heapify(int[] arr, int index, int end) {
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        while (left <= end) {//注意条件
            int maxChild = (right <= end && arr[right] > arr[left]) ? right : left;
            if (arr[index] >= arr[maxChild]) break;//堆化结束
            swap(arr, index, maxChild);
            index = maxChild;
            left = 2 * index + 1;
            right = 2 * index + 2;
        }
    }

    public static void swap(int[] arr, int i, int j) {
        if (i == j) return;
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

    public static void main(String[] args) {
        int[] arr = {4, 57, 87, 23, 23, 1, 8, 57, 8, 1, 587, 89};
        heapSortTest(arr);
        System.out.println(Arrays.toString(arr));
    }
}
